package runnable_functions;


import gui.Main;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
//import java.net.URL;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.concurrent.CountDownLatch;

import javax.xml.parsers.ParserConfigurationException;

import jaxlib.arc.bzip2.BZip2InputStream;

import org.apache.tools.tar.TarEntry;
import org.apache.tools.tar.TarInputStream;
import org.xml.sax.SAXException;

import db.fileParser;
import details.*;


/**
 * @author Tami
 *
 */

public class UpdateFreeDB extends RunnableClasses implements Runnable{


	//	private static String main_url = "http://ftp.freedb.org/pub/freedb/";
	//	private static String download_folder = "C:\\Users\\Tami\\workspace\\Music";
	private static String last_update_file_log = "lastUpdateLogFile.txt";

	private String compressedFileName ;
	private CountDownLatch startSignal;

	public UpdateFreeDB(String compressedFileName,CountDownLatch startSignal){
		this.compressedFileName = compressedFileName;
		this.startSignal = startSignal;
	}



	/* the end has to be .bz2 */
	private  void unBZip2(String bzipFileName) throws FileNotFoundException, IOException, IllegalStateException, SQLException, ParserConfigurationException, SAXException, InterruptedException  {


		System.out.println("function unBZip2 is called\n");

		//create tar input stream from a .tar.bz2 file
		TarInputStream tin = new TarInputStream(new BZip2InputStream( new FileInputStream(new File(bzipFileName))));

		TarEntry entry;
		BufferedReader bin= null;
		ArrayList<BufferedReader> bins = new ArrayList<BufferedReader>();
		ArrayList<fileParser> fileParsers = new ArrayList<fileParser>();
		String dirName = "";
		ArrayList<Cd> cds=null;
		boolean start= true;
		/* get the first entry */
		entry = tin.getNextEntry();
		while (entry != null) {
			if(entry.isDirectory()){
				if(start){
					start = false;
				}
				else {
					//System.out.println("calling to db.update to write the whole folder\n");
					//System.out.println("of the genre :"+dirName);
					fileParsers= getParsedFilesFromTarDir(bins, dirName);
					cds = parserToCd(fileParsers);
					Main.db.openConnection();
					Main.db.updateFromFreeDB(cds, dirName);
					Main.db.closeConnection();

					//System.out.println("number of files in the folder bin :"+dirName+" is : "+ bins.size());

					bins = new ArrayList<BufferedReader>();/* clear*/

				}
				dirName = entry.getName().substring(0, entry.getName().indexOf('/'));


			}
			else if (entry.getSize() > 0) {
				bin = new BufferedReader(new InputStreamReader(tin));



				bins.add(bin);

				//System.out.println("i's bin bin.ready = " +bins.get(bins.indexOf(bin)).ready());

				bins.get(bins.indexOf(bin)).skip(1);

				//System.out.println("bin have been added to bins\n");

			}
			entry = tin.getNextEntry();
			if(entry==null){/* we deal with the last file of the last folder in the zip file*/
				//System.out.println("calling to db.update to write the whole folder\n");
				//System.out.println("of the genre :"+dirName);
				fileParsers= getParsedFilesFromTarDir(bins, dirName);
				cds = parserToCd(fileParsers);
				Main.db.openConnection();
				Main.db.updateFromFreeDB(cds, dirName);
				Main.db.closeConnection();

				//	System.out.println("number of files in the folder bin :"+dirName+" is : "+ bins.size());
				break;
			}
		}

		tin.close();
		closeFileParsers(fileParsers);
		System.out.println("exiting bzip2 file\n");
	}

	private void closeFileParsers(ArrayList<fileParser> fileParsers){
		int size = fileParsers.size();
		for(int i=0;i<size;i++){
			fileParsers.get(i).close();
		}
	}

	private  boolean isTheZipFileNewer(String currPathIndi) throws IOException{
		File update_indi = new File(last_update_file_log);
		if(!update_indi.exists()){
			update_indi.createNewFile();
		}

		BufferedReader in =new BufferedReader(new FileReader(update_indi));
		boolean flag = true;
		String last_update_indi;

		if(in.ready() && (last_update_indi = in.readLine())!=null){
			if(currPathIndi.compareTo(last_update_indi)<=0){

				flag = false;
			}
		}

		in.close();

		return flag;
	}

	private void updateNewerZipFileLog(String curr_update_indi) throws IOException{
		File update_indi = new File(last_update_file_log);
		BufferedWriter out= new BufferedWriter(new FileWriter(update_indi));
		out.write(curr_update_indi);
		out.close();
	}



	private  String getUpdateZipFileIdicator(String zipFileName){
		String indi = zipFileName.substring(zipFileName.lastIndexOf("-")+1,zipFileName.indexOf("."));
		return indi;
	}



	private ArrayList<fileParser> getParsedFilesFromTarDir(ArrayList<BufferedReader> bins,String dirName) throws NumberFormatException, IOException, IllegalStateException, ParserConfigurationException, SAXException, InterruptedException
	{
		int numOfFiles = bins.size();

		ArrayList<fileParser> files = new ArrayList<fileParser>();


		for (int i=0;i<numOfFiles;i++){

			fileParser fp = new fileParser(bins.get(i));

			boolean b = fp.parse();
			if (b){

				if (fp.getDgenre()== null)
				{

					fp.setDgenre(dirName);
				}

				files.add(fp);

			}

		}



		return files;


	}


	private ArrayList<Cd> parserToCd(ArrayList<fileParser> fps) throws SQLException, IllegalStateException, IOException, ParserConfigurationException, SAXException, InterruptedException
	{
		ArrayList<Cd> cds = new ArrayList<Cd>();
		for (fileParser fp : fps)
		{
			Cd cd = new Cd(fp.getParsedTitle(), fp.getDiscId()[0], 0, fp.getParsedArtist(), fp.getDyear(), fp.getDiscLength(), fp.getDgenre(), 0, 0);
			ArrayList<Track> t = new ArrayList<Track>();

			int[] trackLengths = fp.calculateTracksLengths(fp.getTrackOffsets(), fp.getDiscLength());

			int numOfTracks = fp.getTtitles().size();

			for (int i=0; i< numOfTracks; i++)
			{
				String trackArtist;
				String trackTitle;
				if(fp.isVarious() == false)
				{
					trackArtist = fp.getParsedArtist();
					trackTitle = fp.getTtitles().get(i);
				}

				else
				{
					trackArtist = fp.getVarArtists().get(i);
					trackTitle = fp.getParsed_track_titles().get(i);
				}



				Track track = new Track(cd.getAlbom_id(), i+1, trackTitle, trackArtist, trackLengths[i],0);
				t.add(track);

			}

			cd.setTracks(t);
			//cd.addlyrics();
			cds.add(cd);

		}


		return cds;


	}


	@Override
	public void run() {
		boolean isNewUpdate=false;
		try{
			String curr_update_indi =  getUpdateZipFileIdicator(compressedFileName);
			isNewUpdate = isTheZipFileNewer(curr_update_indi);
			if(isNewUpdate){
				long startTime, duration;
				startTime = System.currentTimeMillis();
				unBZip2(compressedFileName);
				duration = (System.currentTimeMillis() - startTime)/1000;
				System.out.println("The update took " + duration + " seconds");
				updateNewerZipFileLog(curr_update_indi);
				System.out.println("ok");
				Main.guiInt.notifySuccess();

			}
			else{
				//gui_int.notifyGeneralError(" this update is not new");
				System.out.println(" this update is not new");
				Main.guiInt.notifyGeneralError(" this update is not new");
			}



		}
		catch(SQLException e){
			Main.guiInt.notifyDBFailure(e.getMessage());

		}
		catch(IOException e){
			Main.guiInt.notifyGeneralError(e.getMessage());
		}
		catch (IllegalStateException e) {
			Main.guiInt.notifyGeneralError(e.getMessage());

		} catch (ParserConfigurationException e) {
			Main.guiInt.notifyGeneralError(e.getMessage());
		} catch (SAXException e) {
			Main.guiInt.notifyGeneralError(e.getMessage());
		} catch (InterruptedException e) {
			Main.guiInt.notifyGeneralError(e.getMessage());
		}
		finally{
			startSignal.countDown();
		}

	}


}

